package mirkofrancuski.battleship;

import java.util.HashMap;

import mirkofrancuski.battleship.db.BoardTable;
import mirkofrancuski.battleship.db.CoordinateTable;
import mirkofrancuski.battleship.db.DatabaseHelper;
import mirkofrancuski.battleship.db.HighScoreInfo;
import mirkofrancuski.battleship.db.IntTable;
import mirkofrancuski.battleship.game.Board;
import mirkofrancuski.battleship.game.Cell;
import mirkofrancuski.battleship.game.ComputerEasy;
import mirkofrancuski.battleship.game.ComputerHard;
import mirkofrancuski.battleship.game.ComputerNormal;
import mirkofrancuski.battleship.game.Coordinates;
import mirkofrancuski.battleship.game.Game;
import mirkofrancuski.battleship.game.Game.PlayerType;
import mirkofrancuski.battleship.game.Player;
import mirkofrancuski.battleship.game.Ship;
import mirkofrancuski.battleship.gui.PlayBoard;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Typeface;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class GameActivity extends MenuActivity implements Player {
	public static final int DIALOG_GAME_VICTORY = 1;
	public static final int DIALOG_GAME_DEFEAT = 2;

	private class ScoreBoard {
		private String SHOTS = "Shots: ";

		private int mCellWidth;

		private Bitmap mPlayerIcon;
		private Bitmap mPlayerShip5, mPlayerShip4, mPlayerShip3, mPlayerShip2;
		private Bitmap mPlayerSunkenShip5, mPlayerSunkenShip4,
				mPlayerSunkenShip3, mPlayerSunkenShip2;

		private Bitmap mComputerIcon;
		private Bitmap mComputerShip5, mComputerShip4, mComputerShip3,
				mComputerShip2;
		private Bitmap mComputerSunkenShip5, mComputerSunkenShip4,
				mComputerSunkenShip3, mComputerSunkenShip2;

		public ScoreBoard() {

			PlayBoard pb = (PlayBoard) findViewById(R.id.game_board_main);
			mCellWidth = pb.getCellWidth();

			LinearLayout layout = (LinearLayout) findViewById(R.id.score_board);
			LayoutParams params = layout.getLayoutParams();
			params.height = mCellWidth * 8;
			params.width = mCellWidth * 7;

			loadBitmaps();

			TextView counter = (TextView) findViewById(R.id.player_shots_number);
			counter.setText(SHOTS + 0);
			// setBitmaps();
			// setSizes();

		}

		public void setPlayerTurn(Game.PlayerType player) {
			LinearLayout user = (LinearLayout) findViewById(R.id.player_scoreboard);
			LinearLayout computer = (LinearLayout) findViewById(R.id.computer_scoreboard);

			if (player == Game.PlayerType.USER) {
				user.setBackgroundResource(R.drawable.selected_player_background);
				computer.setBackgroundResource(R.color.Transparent);
			} else {
				computer.setBackgroundResource(R.drawable.selected_player_background);
				user.setBackgroundResource(R.color.Transparent);
			}
			computer.invalidate();
			user.invalidate();
		}

		public void sunkPlayerShip(Cell ship) {
			switch (ship) {
			case AIRCRAFT_CARRIER:
				((ImageView) findViewById(R.id.player_ship5))
						.setImageBitmap(mPlayerSunkenShip5);
				break;
			case BATTLESHIP:
				((ImageView) findViewById(R.id.player_ship4))
						.setImageBitmap(mPlayerSunkenShip4);
				break;
			case SUBMARINE:
				((ImageView) findViewById(R.id.player_ship3))
						.setImageBitmap(mPlayerSunkenShip3);
				break;
			case CRUISER:
				((ImageView) findViewById(R.id.player_ship3c))
						.setImageBitmap(mPlayerSunkenShip3);
				break;
			case DESTROYER:
				((ImageView) findViewById(R.id.player_ship2))
						.setImageBitmap(mPlayerSunkenShip2);
				break;

			default:
				break;
			}
		}

		public void sunkComputerShip(Cell ship) {
			switch (ship) {
			case AIRCRAFT_CARRIER:
				((ImageView) findViewById(R.id.computer_ship5))
						.setImageBitmap(mComputerSunkenShip5);
				break;
			case BATTLESHIP:
				((ImageView) findViewById(R.id.computer_ship4))
						.setImageBitmap(mComputerSunkenShip4);
				break;
			case SUBMARINE:
				((ImageView) findViewById(R.id.computer_ship3))
						.setImageBitmap(mComputerSunkenShip3);
				break;
			case CRUISER:
				((ImageView) findViewById(R.id.computer_ship3c))
						.setImageBitmap(mComputerSunkenShip3);
				break;
			case DESTROYER:
				((ImageView) findViewById(R.id.computer_ship2))
						.setImageBitmap(mComputerSunkenShip2);
				break;

			default:
				break;
			}
		}

		public void increasePlayerShots() {
			TextView counter = (TextView) findViewById(R.id.player_shots_number);
			String text = counter.getText().toString();

			String subtext = text.substring(SHOTS.length());

			int shots = Integer.parseInt(subtext);
			shots++;
			counter.setText(SHOTS + shots);
		}

		public int getNoOfShots() {
			TextView counter = (TextView) findViewById(R.id.player_shots_number);
			String text = counter.getText().toString();

			String subtext = text.substring(SHOTS.length());

			return Integer.parseInt(subtext);
		}

		public void setNoOfShots(int shotsNo) {
			TextView counter = (TextView) findViewById(R.id.player_shots_number);
			counter.setText(SHOTS + shotsNo);
		}

		private void loadBitmaps() {
			Resources res = getResources();

			mPlayerIcon = Bitmap.createScaledBitmap(
					BitmapFactory.decodeResource(res, R.drawable.user_icon),
					mCellWidth * 2, mCellWidth * 2, true);

			mPlayerShip5 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship5_left_half),
					mCellWidth * 5 / 2, mCellWidth, true);

			mPlayerSunkenShip5 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship5_sunken_left_half),
					mCellWidth * 5 / 2, mCellWidth, true);

			mPlayerShip4 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship4_left_half),
					mCellWidth * 4 / 2, mCellWidth, true);

			mPlayerSunkenShip4 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship4_sunken_left_half),
					mCellWidth * 4 / 2, mCellWidth, true);

			mPlayerShip3 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship3_left_half),
					mCellWidth * 3 / 2, mCellWidth, true);

			mPlayerSunkenShip3 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship3_sunken_left_half),
					mCellWidth * 3 / 2, mCellWidth, true);

			mPlayerShip2 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship2_left_half),
					mCellWidth * 2 / 2, mCellWidth, true);

			mPlayerSunkenShip2 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship2_sunken_left_half),
					mCellWidth * 2 / 2, mCellWidth, true);

			mComputerIcon = Bitmap
					.createScaledBitmap(BitmapFactory.decodeResource(res,
							R.drawable.computer_icon), mCellWidth * 2,
							mCellWidth * 2, true);

			mComputerShip5 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship5_right_half),
					mCellWidth * 5 / 2, mCellWidth, true);

			mComputerSunkenShip5 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship5_sunken_right_half),
					mCellWidth * 5 / 2, mCellWidth, true);

			mComputerShip4 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship4_right_half),
					mCellWidth * 4 / 2, mCellWidth, true);

			mComputerSunkenShip4 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship4_sunken_right_half),
					mCellWidth * 4 / 2, mCellWidth, true);

			mComputerShip3 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship3_right_half),
					mCellWidth * 3 / 2, mCellWidth, true);

			mComputerSunkenShip3 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship3_sunken_right_half),
					mCellWidth * 3 / 2, mCellWidth, true);

			mComputerShip2 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship2_right_half),
					mCellWidth * 2 / 2, mCellWidth, true);

			mComputerSunkenShip2 = Bitmap.createScaledBitmap(BitmapFactory
					.decodeResource(res, R.drawable.ship2_sunken_right_half),
					mCellWidth * 2 / 2, mCellWidth, true);
		}

	}

	private ScoreBoard scoreBoard;
	private PlayBoard mainBoard;
	private PlayBoard secundaryBoard;

	private String playerName;
	private Game gameLoop;

	private Coordinates lastShot = null;
	private String computerLevel;
	private DatabaseHelper m_dbHelper;
	private Player opponent;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_game);

		m_dbHelper = new DatabaseHelper(this);

		scoreBoard = new ScoreBoard();
		mainBoard = (PlayBoard) findViewById(R.id.game_board_main);
		secundaryBoard = (PlayBoard) findViewById(R.id.game_board_secundary);

		// set font
		TextView txt = (TextView) findViewById(R.id.player_shots_number);
		Typeface font = Typeface.createFromAsset(getAssets(), "DueDate.ttf");
		txt.setTypeface(font);

		SharedPreferences sharedPrefs = PreferenceManager
				.getDefaultSharedPreferences(this);
		playerName = sharedPrefs.getString(SettingsActivity.KEY_PREF_USERNAME,
				"");
		computerLevel = sharedPrefs.getString(
				SettingsActivity.KEY_PREF_COMPUTER_PLAYER, "");

	}

	@Override
	protected void onPause() {
		super.onPause();

//		gameLoop.end();
//		SQLiteDatabase db = m_dbHelper.getWritableDatabase();
//		this.save(db);

	}

	@Override
	protected void onResume() {
		super.onResume();

		Board board = getIntent().getParcelableExtra("secundaryBoard");
		if (board != null) { // new game
			secundaryBoard.setBoard(board);

			opponent = getComputer(computerLevel);
			
			gameLoop = new Game(this, opponent);
			gameLoop.start();

		} else { // read from db
//			SQLiteDatabase db = m_dbHelper.getWritableDatabase();
//			this.restore(db);
//
//			gameLoop.start();
		}

	}

	private Player getComputer(String computerLevel) {
		if (computerLevel.equals("Normal")) {
			return new ComputerNormal();
		} else if (computerLevel.equals("Hard")) {
			return new ComputerHard();
		}

		return new ComputerEasy();
	}

	private int computerToInt(String computerLevel) {
		if (computerLevel.equals("Normal")) {
			return 2;
		} else if (computerLevel.equals("Hard")) {
			return 3;
		}

		return 1;
	}

	private String intToComputerString(int value) {
		switch (value) {
		case 1:
			return "Easy";
		case 2:
			return "Normal";
		case 3:
			return "Hard";
		default:
			break;
		}
		return null;
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		menu.findItem(R.id.menu_new_game).setVisible(true);
		return true;
	}

	private void newGame() {
		Intent returnIntent = new Intent();
		setResult(RESULT_OK, returnIntent);
		GameActivity.this.finish();
	}

	private void mainMenu() {
		Intent returnIntent = new Intent();
		setResult(RESULT_CANCELED, returnIntent);
		GameActivity.this.finish();
	}

	private void highScores() {
		Intent returnIntent = new Intent();
		setResult(RESULT_FIRST_USER, returnIntent);
		GameActivity.this.finish();
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.menu_new_game:
			newGame();
			break;
		default:
			return super.onOptionsItemSelected(item);
		}
		return true;
	}

	@Override
	@Deprecated
	protected Dialog onCreateDialog(int id) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setCancelable(false)
				.setPositiveButton("Play again",
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog, int id) {
								newGame();
							}
						})
				.setNegativeButton("Main manu",
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog, int id) {
								mainMenu();
							}
						});

		switch (id) {
		case DIALOG_GAME_VICTORY:
			builder.setTitle(R.string.win_dialog_title);
			builder.setIcon(R.drawable.smiley_boss);

			// highscore
			HighScoreInfo highscore = new HighScoreInfo(playerName,
					computerLevel, getNoOfShots());

			if (m_dbHelper.addHighScore(highscore)) {
				builder.setMessage("New highscore!");
				builder.setNeutralButton("Highscores",
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog, int id) {
								highScores();
							}
						});
			}

			break;

		case DIALOG_GAME_DEFEAT:
			builder.setTitle(R.string.lost_dialog_title);
			builder.setIcon(R.drawable.smiley_beat_shot);
		default:
			break;
		}

		return builder.create();
	}

	private boolean victory = false;
	private Coordinates tempCoordinates = null;
	private Cell tempCell = null;
	private Ship tempShip = null;

	public void gameOver() {
		victory = gameLoop.getWinner().equals(this);

		runOnUiThread(new Runnable() {

			@SuppressWarnings("deprecation")
			@Override
			public void run() {
				if (victory) {
					removeDialog(DIALOG_GAME_VICTORY);
					showDialog(DIALOG_GAME_VICTORY);
				} else
					showDialog(DIALOG_GAME_DEFEAT);
			}
		});

	}

	@Override
	public Coordinates getShotCoordinates() {
		lastShot = mainBoard.getSelectedCoordinates();
		return lastShot;
	}

	@Override
	public Cell takeHit(Coordinates coord) {
		tempCoordinates = coord;
		tempCell = secundaryBoard.takeHit(tempCoordinates);

		runOnUiThread(new Runnable() {

			@Override
			public void run() {
				secundaryBoard.updateHit(tempCoordinates, tempCell);
				scoreBoard.sunkPlayerShip(tempCell);
				synchronized (this) {
					notify();
				}
			}
		});

		return tempCell;
	}

	@Override
	public void resultFromLastShot(Cell cell) {
		tempCell = cell;

		runOnUiThread(new Runnable() {

			@Override
			public void run() {
				mainBoard.updateResult(lastShot, tempCell);
				scoreBoard.increasePlayerShots();
			}
		});

	}

	@Override
	public void resultFromLastShot(Ship ship) {
		tempShip = ship;

		runOnUiThread(new Runnable() {

			@Override
			public void run() {
				mainBoard.updateResult(tempShip);
				scoreBoard.sunkComputerShip(tempShip.shipCell);
				scoreBoard.increasePlayerShots();
			}
		});

	}

	@Override
	public Ship getShip(Cell ship) {
		return secundaryBoard.getBoard().selectPlacedShip(ship);
	}

	private PlayerType tempPlayer;

	public void setPlayerTurn(PlayerType player) {
		tempPlayer = player;

		runOnUiThread(new Runnable() {

			@Override
			public void run() {
				scoreBoard.setPlayerTurn(tempPlayer);
				if (tempPlayer == PlayerType.COMPUTER)
					mainBoard.setClickable(false);
				else
					mainBoard.setClickable(true);

			}
		});

	}

	@Override
	public boolean areAllShipsSunk() {
		return secundaryBoard.areAllShipsSunk() && getNoOfShots() >= 17;
	}

	@Override
	public int getNoOfShots() {
		return scoreBoard.getNoOfShots();
	}

	private static String CLASS_NAME = "Human_Player";

	@Override
	public void save(SQLiteDatabase db) {
		BoardTable.saveBoard(db, mainBoard.getBoard(),
				BoardTable.BOARD_GAME_PLAYER_MAIN);
		BoardTable.saveBoard(db, secundaryBoard.getBoard(),
				BoardTable.BOARD_GAME_PLAYER_SECUNDARY);

		int noOfShots = scoreBoard.getNoOfShots();
		IntTable.addInt(db, CLASS_NAME, "noOfShots", noOfShots);

		HashMap<String, Coordinates> coordinatesHashMap = CoordinateTable
				.getCoordinates(db, CLASS_NAME);
		lastShot = coordinatesHashMap.get("lastShot");
		
		IntTable.addInt(db, CLASS_NAME, "computerLevel", computerToInt(computerLevel));
		
		int isEnd = gameLoop.isEnd() ? 1 : 0;
		int currentPlayerIndex = gameLoop.getCurrentPlayerIndex();
		
		IntTable.addInt(db, CLASS_NAME, "isEnd", isEnd);
		IntTable.addInt(db, CLASS_NAME, "currentPlayerIndex", currentPlayerIndex);
		
		
		opponent.save(db);

	}

	@Override
	public void restore(SQLiteDatabase db) {
		Board enemyBoard = BoardTable.restoreBoard(db,
				BoardTable.BOARD_GAME_PLAYER_MAIN);
		Board myBoard = BoardTable.restoreBoard(db,
				BoardTable.BOARD_GAME_PLAYER_SECUNDARY);

		mainBoard.setBoard(enemyBoard);
		secundaryBoard.setBoard(myBoard);		

		HashMap<String, Coordinates> coordinatesHashMap = CoordinateTable.getCoordinates(db, CLASS_NAME);
		lastShot = coordinatesHashMap.get("lastShot");
		
		HashMap<String, Integer> hashMap = IntTable.getInts(db, CLASS_NAME);
		int noOfShots = hashMap.get("noOfShots");
		scoreBoard.setNoOfShots(noOfShots);
		
		computerLevel = intToComputerString(hashMap.get("computerLevel"));
		Player opponent = getComputer(computerLevel);
		
		int isEnd = hashMap.get("isEnd");
		int currentPlayerIndex = hashMap.get("currentPlayerIndex");
		
		opponent.restore(db);
		
		gameLoop = new Game(this, opponent, currentPlayerIndex, isEnd == 1);
		
		for(Cell cell: Board.ships){
			if(myBoard.isSunk(cell)){
				scoreBoard.sunkPlayerShip(cell);
			}
			if(enemyBoard.isSunk(cell)){
				scoreBoard.sunkPlayerShip(cell);
			}
		}
		
		

	}

}
